home *** CD-ROM | disk | FTP | other *** search
/ Windows Expert / Windows Expert.iso / utility / uwserver.zip / uwserver.tar / lib / uw_new.c < prev    next >
C/C++ Source or Header  |  1991-01-25  |  6KB  |  213 lines

  1. /*
  2.  *    uw library - uw_new
  3.  *
  4.  * Copyright 1986 by John D. Bruner.  All rights reserved.  Permission to
  5.  * copy this program is given provided that the copy is not sold and that
  6.  * this copyright notice is included.
  7.  */
  8. #include <sys/types.h>
  9. #include <sys/socket.h>
  10. #include <netinet/in.h>
  11. #include <sys/uio.h>
  12. #include <strings.h>
  13. #include <signal.h>
  14. #include <netdb.h>
  15. #include <ctype.h>
  16. #include "openpty.h"
  17.  
  18. #include "uwlib.h"
  19.  
  20. extern char *malloc();
  21. extern char *getenv();
  22.  
  23. #ifndef htons
  24. /* These should have been defined in <netinet/in.h>, but weren't (in 4.2BSD) */
  25. extern unsigned short htons(), ntohs();
  26. extern unsigned long htonl(), ntohl();
  27. #endif
  28.  
  29. UWIN
  30. uw_new(uwtype, sin)
  31. uwtype_t uwtype;
  32. struct sockaddr_in *sin;
  33. {
  34.     register UWIN uwin;
  35.     register char *cp, c;
  36.     register int len;
  37.     register int ctlfd;
  38.     int rdsz;
  39.     auto int namelen;
  40.     auto struct sockaddr_in sa, datasin, ctlsin;
  41.     auto struct uwipc uwip;
  42.     extern int errno;
  43.  
  44.     /*
  45.      * If our caller didn't supply an address for us to contact,
  46.      * look in the environment to find it.
  47.      */
  48.     if (sin == (struct sockaddr_in *)0) {
  49.         if ((cp = getenv(INET_ENV)) == (char *)0) {
  50.             uwerrno = UWE_NXSERV;
  51.             return((UWIN)0);
  52.         }
  53.         sin = &sa;
  54.         sa.sin_family = AF_INET;
  55.         sa.sin_addr.s_addr = 0;
  56.         sa.sin_port = 0;
  57.         bzero(sa.sin_zero, sizeof sa.sin_zero);
  58.         for ( ; isxdigit(c = *cp); cp++) {
  59.             /* Pyramid compiler blows this, must use left shift */
  60.             /* sa.sin_addr.s_addr *= 16; */
  61.             sa.sin_addr.s_addr <<= 4;
  62.             if (isdigit(c))
  63.                 sa.sin_addr.s_addr += c-'0';
  64.             else if (islower(c))
  65.                 sa.sin_addr.s_addr += c-'a' + 10;
  66.             else
  67.                 sa.sin_addr.s_addr += c-'A' + 10;
  68.         }
  69.         if (c == '.') {
  70.             for (cp++; isdigit(c = *cp); cp++)
  71.                 sa.sin_port = sa.sin_port*10 + c-'0';
  72.         }
  73.         if (sa.sin_addr.s_addr == 0 || sa.sin_port == 0 ||
  74.             c != '\0') {
  75.             /* bad address */
  76.             uwerrno = UWE_INVAL;
  77.             return((UWIN)0);
  78.         }
  79.         sa.sin_addr.s_addr = htonl(sa.sin_addr.s_addr);
  80.         sa.sin_port = htons(sa.sin_port);
  81.     }
  82.  
  83.     /*
  84.      * Allocate space for a new window structure.
  85.      */
  86.     if ((uwin = (UWIN)malloc(sizeof(*uwin))) == (UWIN)0) {
  87.         uwerrno = UWE_NOMEM;
  88.         return((UWIN)0);
  89.     }
  90.     uwin->uwi_type = uwtype;
  91.     for (len=0; len < UW_NUMOPTS; len++) /* "len" is a convenient "int" */
  92.         uwin->uwi_options[len].uwi_optfn = (uwfnptr_t)0;
  93.     
  94.     /*
  95.      * Create sockets for the data and control file descriptors.
  96.      */
  97.     if ((uwin->uwi_datafd = socket(AF_INET, SOCK_STREAM, 0)) < 0 ||
  98.         (uwin->uwi_ctlfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
  99.         if (uwin->uwi_datafd >= 0)
  100.             (void)close(uwin->uwi_datafd);
  101.         return((UWIN)0);
  102.     }
  103.  
  104.     /*
  105.      * Bind these sockets to a local address.  We figure out the
  106.      * local machine's host number and use it if possible; otherwise,
  107.      * we fall back to 127.0.0.1 (loopback device).  After binding,
  108.      * we determine the port number for the control socket, since we
  109.      * must send that to the server.  Connect to the server.
  110.      */
  111.     datasin.sin_family = AF_INET;
  112.     datasin.sin_port = 0;
  113.     bzero(datasin.sin_zero, sizeof datasin.sin_zero);
  114.     getmyaddr(&datasin.sin_addr);
  115.     ctlsin.sin_family = AF_INET;
  116.     ctlsin.sin_port = 0;
  117.     bzero(ctlsin.sin_zero, sizeof ctlsin.sin_zero);
  118.     getmyaddr(&ctlsin.sin_addr);
  119.     if (bind(uwin->uwi_datafd, (struct sockaddr *)&datasin, sizeof datasin) < 0 ||
  120.         bind(uwin->uwi_ctlfd, (struct sockaddr *)&ctlsin, sizeof ctlsin) < 0 ||
  121.         listen(uwin->uwi_ctlfd, 1) < 0) {
  122.         uwerrno = UWE_ERRNO;
  123.         goto error;
  124.     }
  125.     namelen = sizeof ctlsin;
  126.     (void)getsockname(uwin->uwi_ctlfd, (char *)&ctlsin, &namelen);
  127.  
  128.     if (connect(uwin->uwi_datafd, sin, sizeof(struct sockaddr_in)) < 0) {
  129.         uwerrno = UWE_ERRNO;
  130.         goto error;
  131.     }
  132.  
  133.     /*
  134.      * Now we have enough information to build the new-window command
  135.      * and send it to the server.  The initial command is sent to the
  136.      * data port.  Next, we wait for a connection from the server to
  137.      * our data socket.  Finally, we expect the server to send us a
  138.      * new window status message on the data fd.
  139.      */
  140.     len = sizeof uwip.uwip_neww + (char *)&uwip.uwip_neww - (char *)&uwip;
  141.     uwip.uwip_len = htons(len);
  142.     uwip.uwip_cmd = htons(UWC_NEWW);
  143.     uwip.uwip_neww.uwnw_id = 0;    /* let server choose this */
  144.     uwip.uwip_neww.uwnw_type = htons(uwtype);
  145.     uwip.uwip_neww.uwnw_ctlport = ctlsin.sin_port;/* byte order correct */
  146.     if (write(uwin->uwi_datafd, (char *)&uwip, len) < 0) {
  147.         uwerrno = UWE_ERRNO;
  148.         goto error;
  149.     }
  150.     
  151.     namelen = sizeof ctlsin;
  152.     if ((ctlfd = accept(uwin->uwi_ctlfd, (struct sockaddr_in *)&ctlsin, &namelen)) < 0) {
  153.         uwerrno = UWE_ERRNO;
  154.         goto error;
  155.     }
  156.     (void)close(uwin->uwi_ctlfd);
  157.     uwin->uwi_ctlfd = ctlfd;
  158.     uw_optinit(ctlfd, uwin);
  159.  
  160.     cp = (char *)&uwip.uwip_len;
  161.     rdsz = sizeof uwip.uwip_len;
  162.     while (rdsz > 0 && (len=read(uwin->uwi_datafd, cp, rdsz)) > 0) {
  163.         cp += len;
  164.         rdsz -= len;
  165.     }
  166.     if (len > 0) {
  167.         rdsz = htons(uwip.uwip_len) - sizeof uwip.uwip_len;
  168.         while (rdsz > 0 && (len=read(uwin->uwi_datafd, cp, rdsz)) > 0) {
  169.             cp += len;
  170.             rdsz -= len;
  171.         }
  172.     }
  173.     if (len <= 0) {
  174.         uwerrno = UWE_ERRNO;
  175.         goto error;
  176.     }
  177.     uwerrno = uwin->uwi_uwerr = ntohs(uwip.uwip_status.uwst_err);
  178.     errno = uwin->uwi_errno = ntohs(uwip.uwip_status.uwst_errno);
  179.     if (uwin->uwi_uwerr != UWE_NONE)
  180.         goto error;
  181.     uwin->uwi_id = ntohl(uwip.uwip_status.uwst_id);
  182.     return(uwin);
  183.  
  184. error:
  185.     (void)close(uwin->uwi_datafd);
  186.     (void)close(uwin->uwi_ctlfd);
  187.     free((char *)uwin);
  188.     return((UWIN)0);
  189. }
  190.  
  191. static
  192. getmyaddr(addr)
  193. struct in_addr *addr;
  194. {
  195.     register struct hostent *h;
  196.     char hostname[32];
  197.     static int once = 1;
  198.     static struct in_addr myaddr;
  199.  
  200.     if (once) {
  201.         if (gethostname(hostname, sizeof hostname) < 0) {
  202.             (void)strncpy(hostname, "localhost", sizeof hostname-1);
  203.             hostname[sizeof hostname-1] = '\0';
  204.         }
  205.         if ((h = gethostbyname(hostname)) != (struct hostent *)0)
  206.             myaddr = *(struct in_addr *)h->h_addr;
  207.         else
  208.             myaddr.s_addr = htonl(0x7f000001L);
  209.         once = 0;
  210.     }
  211.     *addr = myaddr;
  212. }
  213.